﻿using Avalonia;
using Avalonia.Controls;
using LightCAD.Core;
using LightCAD.Core.Elements;
using LightCAD.Core.Filters;
using LightCAD.Runtime;
using SkiaSharp;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Drawing.Drawing2D;
using System.Linq;
using System.Linq.Expressions;
using System.Numerics;
using System.Runtime.ConstrainedExecution;
using System.Runtime.Intrinsics.X86;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Xml.Linq;
using static LightCAD.Core.Elements.LcPolyLine;
using static LightCAD.Drawing.ArcAction;
using static LightCAD.Runtime.ElementAction;
using static OpenTK.Graphics.OpenGL.GL;
using static System.Runtime.InteropServices.JavaScript.JSType;

namespace LightCAD.Drawing
{
    public class ArcAction : ElementAction
    {
        public static string CommandName;
        public static LcCreateMethod[] CreateMethods;
        private Vector2d startPoint;
        private Vector2d endPoint;
        private Vector2d midPoint;
        private Vector2d centerPoint;
        private DrawArcType drawArcType;
        private double startangle;
        private double angle;
        private double arcLength;
        private double radius;
        public enum DrawArcType
        {
            ArcCenter = 0,
            ArcThreePoint = 1,

        }
        static ArcAction()
        {

            CreateMethods = new LcCreateMethod[3];
            CreateMethods[0] = new LcCreateMethod()
            {
                Name = "CreateARC",
                Description = "创建弧线",
                Steps = new LcCreateStep[]
                {

                    new LcCreateStep { Name=  "Step0", Options= "ARC指定圆弧的起点或 [圆心(C)]:" },
                    new LcCreateStep { Name=  "Step1", Options= "ARC指定圆弧的第二个点或 [圆心(C)/端点(E)]:" },
                    new LcCreateStep { Name=  "Step2", Options= "ARC指定圆弧的端点:" },
                    new LcCreateStep { Name=  "Step3", Options= "ARC指定圆弧的圆心:" },
                    new LcCreateStep { Name=  "Step4", Options= "ARC指定圆弧的起点:" },
                    new LcCreateStep { Name=  "Step5", Options= "ARC指定圆弧的端点(按住 Ctrl 键以切换方向)或 [角度(A)/弦长(L)]:" },
                }
            };

        }

        internal static void Initilize()
        {
            ElementActions.Arc = new ArcAction();
            LcDocument.ElementActions.Add(BuiltinElementType.Arc, ElementActions.Arc);
        }
        private InElementsInputer InElementsInputer { get; set; }
        private ElementSetInputer ElementInputers { get; set; }
        private ElementInputer ElementInputer { get; set; }
        private CmdTextInputer CmdTextInputer { get; set; }
        private PointInputer PointInputer { get; set; }
        private ArcAction() { }
        public ArcAction(DocumentRuntime docRt) : base(docRt)
        {
            docRt.CommandCtrl.WriteInfo("命令：ARC");
        }

        public async void ExecCreate(string[] args = null)
        {
            //DocumentManager.CurrentRecorder.BeginAction("PolyLine");
            this.StartCreating();

            var curMethod = CreateMethods[0];

            this.PointInputer = new PointInputer(this.docRt);
            string name = "";
            string description = "";
            Step0:

            var step0 = curMethod.Steps[0];
            var result0 = await PointInputer.Execute(step0.Options);
            if (PointInputer.isCancelled) { this.Cancel(); return; }
            // zcb: 增加Res0为空的判定
            if (result0 == null)
            {
                this.Cancel();
                goto End;
            }
            if (result0.Value == null)
            {
                if (result0.Option != null)
                {
                    goto Step0;
                    //TODO:AutoCAD画线输入一个数字，是怎么确定点的？
                }
                else
                    if (result0.Option == "C")
                { }
                else
                    goto Step1;
            }
            else
            {
                this.startPoint = (Vector2d)result0.Value;
                goto Step1;
            }
            Step1:
            this.drawArcType = DrawArcType.ArcThreePoint;
            var step1 = curMethod.Steps[1];
            var result1 = await PointInputer.Execute(step1.Options);
            if (PointInputer.isCancelled)
            {
                this.Cancel();
                return;
            }
            if (result1.Value == null)
            {


            }
            else
            {
                this.midPoint = (Vector2d)result1.Value;
                PlineSegment pl = new PlineSegment();
               
                goto Step2;
            }

            Step2:
            var step2 = curMethod.Steps[2];
            var result2 = await PointInputer.Execute(step2.Options);
            if (PointInputer.isCancelled)
            {
                this.Cancel();
                goto End;
            }
            if (result2.Value == null)
            {


            }
            else
            {
                this.endPoint = (Vector2d)result2.Value;
                Arc2d.ArcFrom3Points(startPoint, endPoint, midPoint, out Vector2d cen, out double rad, out double sa, out double ea);
                centerPoint = cen;
                this.startangle = ThreePointGetAngle(startPoint, midPoint, endPoint);
                this.angle = ThreePointGetAngle(startPoint, cen, endPoint);
                this.radius = rad;
                if (startangle < 90) {
                    this.angle = 360 - this.angle;
                }
                CreateArc();
                //注释掉 by:Zcb 2023-07-21 21:42
                goto End;
            }

            End:
            this.EndCreating();
            //if (Segments.Count > 0)
            //{

            //    //  DocumentManager.CurrentRecorder.EndAction();
            //}
            //else
            //{
            //    //  DocumentManager.CurrentRecorder.CancleAction(); 

            //}
        }

        public double ThreePointGetAngle(Vector2d startpoint, Vector2d midpoint, Vector2d endpoint) {
            double angle = 0;

            // 向量 m=(x1,y1,z1), n=(x2,y2,z2)
            Vector2d vecstart = startpoint - midpoint;
            Vector2d vecend = endpoint - midpoint;
            //cos = (x1x2+y1y2+z1z2) /|a||b|
            var cos = (vecstart.X * vecend.X + vecstart.Y * vecend.Y) / (Math.Sqrt(vecstart.X * vecstart.X + vecstart.Y * vecstart.Y) * Math.Sqrt(vecend.X * vecend.X + vecend.Y * vecend.Y));
            angle= 180 * Math.Acos(cos) / Math.PI;
            return angle;
        }

        private bool CreateArc()
        {
            var doc = this.docRt.Document;
            DocumentManager.CurrentRecorder.BeginAction("arc");
            var LcArc = doc.CreateObject<LcArc>();
            LcArc.Center = this.centerPoint;
            LcArc.Radius = this.radius;
            LcArc.StartAngle = this.startangle;
            LcArc.EndAngle = this.angle;
            doc.ModelSpace.InsertElement(LcArc);
            this.docRt.Action.ClearSelects();
            DocumentManager.CurrentRecorder.EndAction();
            return true;
        }
        public override void Cancel()
        {
            base.Cancel();
            this.vportRt.SetCreateDrawer(null);
            //TODO:
            this.EndCreating();
        }
        private void test()
        {
            // this.vportRt.Renderer.DrawRect()
        }

        public override void Draw(SKCanvas canvas, LcElement element, Vector2d offset)
        {
            var grp = element as LcArc;
            float x1 = (float)(grp.Center.X - grp.Radius);
            float y1 = (float)(grp.Center.Y - grp.Radius);
            float x2 = (float)(grp.Center.X + grp.Radius);
            float y2 = (float)(grp.Center.Y + grp.Radius);
            SKRect skrect = new SKRect(x1, y1, x2, y2);
            using (var elePen = new SKPaint { Color = new SKColor(element.GetColorValue()), IsStroke = true })
            {
                canvas.DrawArc(skrect, (float)grp.EndAngle, (float)grp.StartAngle, false, elePen);
            }
            
        }

        public override void CreateElement(LcElement element, Matrix3d matrix)
        {
            var grp = element as LcGroup;
            foreach (var ele in grp.Elements)
            {
                var eleAction = (ele.RtAction as ElementAction);
                eleAction.CreateElement(ele, matrix);
            }
        }
        public override void CreateElement(LcElement element, Vector2d basePoint, double scaleFactor)
        {
            var grp = element as LcGroup;
            foreach (var ele in grp.Elements)
            {
                var eleAction = (ele.RtAction as ElementAction);
                eleAction.CreateElement(ele, basePoint, scaleFactor);
            }

        }
        public override void CreateElement(LcElement element, Vector2d basePoint, Vector2d scaleVector)
        {
            var grp = element as LcGroup;
            foreach (var ele in grp.Elements)
            {
                var eleAction = (ele.RtAction as ElementAction);
                eleAction.CreateElement(ele, basePoint, scaleVector);
            }

        }


        /// <summary>
        /// 获取两条线的夹角  
        /// </summary>
        /// <param name="line1start"></param>
        /// <param name="line1End"></param>
        /// <param name="line2start"></param>
        /// <param name="line2End"></param>
        /// <returns></returns>
        public double GetDegreesByTwoLine(Vector2d line1start, Vector2d line1End, Vector2d line2start, Vector2d line2End)
        {
            double x1 = line1start.X;
            double y1 = line1start.Y;
            double x2 = line1End.X;
            double y2 = line1End.Y;
            double x3 = line2start.X;
            double y3 = line2start.Y;
            double x4 = line2End.X;
            double y4 = line2End.Y;

            // 计算线段的向量表示
            double v1x = x2 - x1;
            double v1y = y2 - y1;
            double v2x = x4 - x3;
            double v2y = y4 - y3;

            // 计算向量的内积
            double dotProduct = v1x * v2x + v1y * v2y;

            // 计算向量的长度
            double magnitudeV1 = Math.Sqrt(v1x * v1x + v1y * v1y);
            double magnitudeV2 = Math.Sqrt(v2x * v2x + v2y * v2y);

            // 计算夹角余弦值
            double cosine = dotProduct / (magnitudeV1 * magnitudeV2);

            // 将夹角余弦值转换为角度
            double angleRadians = Math.Acos(cosine);
            double angleDegrees = angleRadians * 180 / Math.PI;
            return angleDegrees;
        }
        public bool IsPlugAng(Vector2d line1start, Vector2d line1End, Vector2d line2start, Vector2d line2End)
        {
            double x1 = line1start.X;
            double y1 = line1start.Y;
            double x2 = line1End.X;
            double y2 = line1End.Y;
            double x3 = line2start.X;
            double y3 = line2start.Y;
            double x4 = line2End.X;
            double y4 = line2End.Y;
            if (x1 == x2)
            {
                if (x4 < x1)
                {
                    return true;

                }
                else
                {
                    return false;

                }
            }
            else
                if (y1 == y2)
            {
                if (y4 > y1)
                {
                    return true;

                }
                else
                {
                    return false;
                }
            }
            else
            {
                //             a = ( x1, y1) b = (x2, y2)
                //a×b = x1y2 - x2y1
                //若结果为正，则向量b在a的逆时针方向
                //否则，b在a的顺时针方向


                double xa = x2 - x1;
                double ya = y2 - y1;
                double xb = x4 - x3;
                double yb = y4 - y3;
                double angle = xa * yb - xb * ya;
                if (angle > 0)
                { return true; }
                else
                { return false; }
                //# 计算斜率
                //double m1 = (y2 - y1) / (x2 - x1);
                //double m2 = (y4 - y3) / (x4 - x3);
                //double angle = Math.Abs(Math.Tan(m2) - Math.Tan(m1));


                ////if (x2 > x1 && y2 > y1)
                ////{
                ////    if (m2 < m1)
                ////        return false;
                ////}
                ////else if (x2 < x1 && y2 > y1)
                ////{
                ////    if (m2 > m1)
                ////        return false;
                ////}
                ////else if (x2 < x1 && y2 < y1)
                ////{
                ////    if (m2 < m1)
                ////        return false;
                ////}
                ////else if (x2 > x1 && y2 < y1)
                ////{
                ////    if (m2 > m1)
                ////        return false;
                ////}
                //double angle1 = Math.Tan((m2 - m1) / (1 + m1 * m2));
                //if (angle1 > 0)
                //{ return false; }
                //else
                //{ return true; }



            }
        }
        public int IsTopInLine(Vector2d line1start, Vector2d line1End, Vector2d point)
        {
            Vector2d S;
            Vector2d E;
            //if (line1start.X < line1End.X)
            //{
            //    S = line1start;
            //    E = line1End;

            //}
            //else
            //   if (line1start.X == line1End.X)
            //{
            //    if (line1start.Y < line1End.Y)
            //    {
            //        S = line1start;
            //        E = line1End;

            //    }
            //    else
            //    {
            //        S = line1End;
            //        E = line1start;


            //    }
            //}
            //else
            //{
            S = line1End;
            E = line1start;

            // }
            double Tmp = (S.Y - E.Y) * point.X + (E.X - S.X) * point.Y + S.X * E.Y - E.X * S.Y;
            if (Tmp == 0)
            {
                return 0;
            }
            if (Tmp > 0)
            {
                return 1;
            }
            else
            { return -1; }
            //                Tmp > 0 在左侧

            //Tmp = 0 在线上

            //Tmp < 0 在右侧
        }
        public Vector2d GetVerticalpoint(Vector2d point, Vector2d center, Vector2d spoint, double ANG)
        {
            double x1 = point.X;
            double y1 = point.Y;
            double x2 = center.X;
            double y2 = center.Y;
            double x;
            double y;
            if (x1 == x2)
            {
                y = spoint.Y;
                x = x1;
            }
            else
            if (y1 == y2)
            {
                y = y1;
                x = spoint.X;
                //return (new(x1, y1 + 1));
            }
            else
            {
                double k1 = (y2 - y1) / (x2 - x1);


                double b1 = y1 - k1 * x1;
                double k = -1 / k1;
                double b = spoint.Y - k * spoint.X;
                x = (b1 - b) / (k - k1);
                y = k * x + b;

            }

            if (ANG < 180)
            {
                Matrix3d matrix31 = Matrix3d.Move(new Vector2d(x, y), point);
                return matrix31.MultiplyPoint(spoint);

            }
            else

            {
                Matrix3d matrix31 = Matrix3d.Move(spoint, point);
                return matrix31.MultiplyPoint(new Vector2d(x, y));
            }





        }
        public override void DrawTemp(SKCanvas canvas)
        {


        }
        public override void Draw(SKCanvas canvas, LcElement element, Matrix3d matrix)
        {


        }

        public override ControlGrip[] GetControlGrips(LcElement element)
        {
            var group = element as LcGroup;
            var grips = new List<ControlGrip>();
            var gripCenter = new ControlGrip
            {
                Element = group,
                Name = "Center",
                Position = group.BoundingBox.Center
            };
            grips.Add(gripCenter);
            return grips.ToArray();
        }
        private string _gripName;
        private Vector2d _position;
        private Vector2d _endDrag;
        private LcGroup _group;

        public override void SetDragGrip(LcElement element, string gripName, Vector2d position, bool isEnd)
        {
            _group = element as LcGroup;

            if (!isEnd)
            {
                _gripName = gripName;
                _position = position;
            }
            else
            {
                if (gripName == "Center")
                {
                    var delta = position - _group.BoundingBox.Center;
                    _group.Translate(delta);
                }
            }
        }


        public override void DrawDragGrip(SKCanvas canvas)
        {
            if (_group == null) return;

            var offset = _position - _group.BoundingBox.Center;
            foreach (var ele in _group.Elements)
            {
                (ele.RtAction as ElementAction).Draw(canvas, ele, offset);
            }
        }

    }
}
